﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace BToolkit.ExeUtils
{
    /// <summary>
    /// 三张图实现无限拖动(每页支持上下滚动请使用ThreeScrollerPro)
    /// </summary>
    public class ThreeScroller : MonoBehaviour
    {
        public enum Direction
        {
            Horizontal, Vertical
        }
        public Direction direction = Direction.Horizontal;
        public float pageDistance = 1920;
        [Space]
        public TextureLoaderVideo loader1;
        public TextureLoaderVideo loader2;
        public TextureLoaderVideo loader3;
        [Space]
        public BButton btnPrevious;
        public BButton btnNext;

        public RectTransform rectTransform { get { return transform as RectTransform; } }
        public int currTextureIndex { get; private set; }
        List<TextureLoaderVideo> loaders;
        Vector2 downPos, previousPos, targetPos;
        bool isDraging, isMoving;
        string[] paths = new string[0];
        bool nextSuccess, previousSuccess;
        Action<int> onChange;
        Canvas _parentCanvas;
        Canvas ParentCanvas
        {
            get
            {
                if (!_parentCanvas)
                {
                    _parentCanvas = GetComponentInParent<Canvas>();
                }
                return _parentCanvas;
            }
        }
        float t, b, c, d = 0.3f;

        void Awake()
        {
            loaders = new List<TextureLoaderVideo>() { loader1, loader2, loader3, };

            if (btnPrevious)
            {
                btnPrevious.AddClick(() =>
                {
                    Previous();
                });
            }
            if (btnNext)
            {
                btnNext.AddClick(() =>
                {
                    Next();
                });
            }
        }

        public void SetContent(string[] paths, float pageDistance, Action<int> onChange = null)
        {
            //Debug.Log($"count:{paths.Length}");
            this.paths = paths;
            this.pageDistance = pageDistance;
            this.onChange = onChange;
            if (direction == Direction.Horizontal)
            {
                loaders[0].rectTransform.anchoredPosition = new Vector2(-pageDistance, 0);
                loaders[1].rectTransform.anchoredPosition = new Vector2(0, 0);
                loaders[2].rectTransform.anchoredPosition = new Vector2(pageDistance, 0);
            }
            else
            {
                loaders[0].rectTransform.anchoredPosition = new Vector2(0, pageDistance);
                loaders[1].rectTransform.anchoredPosition = new Vector2(0, 0);
                loaders[2].rectTransform.anchoredPosition = new Vector2(0, -pageDistance);
            }
            currTextureIndex = 0;
            if (paths.Length <= 1)
            {
                loaders[0].gameObject.SetActive(false);
                loaders[1].gameObject.SetActive(true);
                loaders[2].gameObject.SetActive(false);
                if (paths.Length == 1)
                {
                    loaders[1].LoadByFullPath(paths[currTextureIndex], false);
                }
            }
            else
            {
                loaders[0].gameObject.SetActive(false);
                loaders[1].gameObject.SetActive(true);
                loaders[2].gameObject.SetActive(true);
                loaders[1].LoadByFullPath(paths[currTextureIndex], false, true);
                loaders[2].LoadByFullPath(paths[currTextureIndex + 1], false, false);
            }
        }

        void Update()
        {
            if (Input.GetMouseButtonDown(0))
            {
                OnTouchDown();
            }

            Vector2 pos = loaders[1].rectTransform.anchoredPosition;
            if (isDraging)
            {
                Vector2 _pos = BUtils.ScreenToUGUIPoint(Input.mousePosition, ParentCanvas);
                Vector2 delta = _pos - previousPos;
                previousPos = _pos;
                pos += delta;
            }
            else
            {
                if (isMoving)
                {
                    if (t < d)
                    {
                        t += Time.deltaTime;
                        if (t > d) t = d;
                        if (direction == Direction.Horizontal)
                        {
                            pos.x = EaseExpoOut(t, b, c, d);
                        }
                        else
                        {
                            pos.y = EaseExpoOut(t, b, c, d);
                        }
                    }
                    else
                    {
                        isMoving = false;
                        targetPos = Vector2.zero;
                        if (nextSuccess)
                        {
                            onChange?.Invoke(currTextureIndex);
                            TextureLoaderVideo last = loaders[0];
                            loaders.RemoveAt(0);
                            loaders.Add(last);
                            loaders[0].PauseVideo();
                            if (loaders[1].isVideo) loaders[1].PlayVideo(false, null);
                            loaders[2].PauseVideo();
                            last.rectTransform.SetAsLastSibling();
                            pos = Vector2.zero;
                            if (currTextureIndex < paths.Length - 1)
                            {
                                if (!last.gameObject.activeSelf) last.gameObject.SetActive(true);
                                last.LoadByFullPath(paths[currTextureIndex + 1], false, false);
                            }
                            else
                            {
                                if (last.gameObject.activeSelf) last.gameObject.SetActive(false);
                            }
                            nextSuccess = false;
                        }
                        else if (previousSuccess)
                        {
                            onChange?.Invoke(currTextureIndex);
                            List<TextureLoaderVideo> bridge = new List<TextureLoaderVideo>() { loaders[2], loaders[0], loaders[1] };
                            loaders = bridge;
                            TextureLoaderVideo first = loaders[0];
                            loaders[0].PauseVideo();
                            if (loaders[1].isVideo) loaders[1].PlayVideo(false, null);
                            loaders[2].PauseVideo();
                            first.rectTransform.SetAsFirstSibling();
                            pos = Vector2.zero;
                            if (currTextureIndex > 0)
                            {
                                if (!first.gameObject.activeSelf) first.gameObject.SetActive(true);
                                first.LoadByFullPath(paths[currTextureIndex - 1], false, false);
                            }
                            else
                            {
                                if (first.gameObject.activeSelf) first.gameObject.SetActive(false);
                            }
                            previousSuccess = false;
                        }
                    }
                }
            }
            if (direction == Direction.Horizontal)
            {
                float y = loaders[1].rectTransform.anchoredPosition.y;
                loaders[0].rectTransform.anchoredPosition = new Vector2(pos.x - pageDistance, y);
                loaders[1].rectTransform.anchoredPosition = new Vector2(pos.x, y);
                loaders[2].rectTransform.anchoredPosition = new Vector2(pos.x + pageDistance, y);
            }
            else
            {
                float x = loaders[1].rectTransform.anchoredPosition.x;
                loaders[0].rectTransform.anchoredPosition = new Vector2(x, pos.y + pageDistance);
                loaders[1].rectTransform.anchoredPosition = new Vector2(x, pos.y);
                loaders[2].rectTransform.anchoredPosition = new Vector2(x, pos.y - pageDistance);
            }

            if (Input.GetMouseButtonUp(0))
            {
                OnTouchUp();
            }
        }

        private void OnTouchDown()
        {
            if (!isMoving)
            {
                downPos = previousPos = BUtils.ScreenToUGUIPoint(Input.mousePosition, ParentCanvas);
                isDraging = true;
                isMoving = true;
            }
        }

        private void OnTouchUp()
        {
            if (isDraging)
            {
                isDraging = false;
                Vector2 pos = BUtils.ScreenToUGUIPoint(Input.mousePosition, ParentCanvas);
                float dis = pageDistance * 0.1f;
                if (direction == Direction.Horizontal)
                {
                    if (downPos.x - pos.x > dis && currTextureIndex < paths.Length - 1 && currTextureIndex < paths.Length - 1)
                    {
                        Next();
                        return;
                    }
                    if (pos.x - downPos.x > dis && currTextureIndex > 0 && currTextureIndex > 0)
                    {
                        Previous();
                        return;
                    }
                }
                else
                {
                    if (pos.y - downPos.y > dis && currTextureIndex < paths.Length - 1 && currTextureIndex < paths.Length - 1)
                    {
                        Next();
                        return;
                    }
                    if (downPos.y - pos.y > dis && currTextureIndex > 0 && currTextureIndex > 0)
                    {
                        Previous();
                        return;
                    }
                }
                InitTween(Vector2.zero);
            }
        }

        void Previous()
        {
            if (currTextureIndex > 0 && currTextureIndex > 0)
            {
                isMoving = true;
                currTextureIndex--;
                targetPos = direction == Direction.Horizontal ? new Vector2(pageDistance, 0) : new Vector2(0, -pageDistance);
                previousSuccess = true;
                InitTween(targetPos);
            }
        }

        void Next()
        {
            if (currTextureIndex < paths.Length - 1 && currTextureIndex < paths.Length - 1)
            {
                isMoving = true;
                currTextureIndex++;
                targetPos = direction == Direction.Horizontal ? new Vector2(-pageDistance, 0) : new Vector2(0, pageDistance);
                nextSuccess = true;
                InitTween(targetPos);
            }
        }

        void InitTween(Vector2 toPos)
        {
            t = 0;
            if (direction == Direction.Horizontal)
            {
                b = loaders[1].rectTransform.anchoredPosition.x;
                c = toPos.x - b;
            }
            else
            {
                b = loaders[1].rectTransform.anchoredPosition.y;
                c = toPos.y - b;
            }
        }

        float EaseExpoOut(double t, double b, double c, double d)
        {
            if (t == d)
            {
                return (float)(b + c);
            }
            else
            {
                return (float)(c * (-Math.Pow(2, -10 * t / d) + 1) + b);
            }
        }
    }
}